<template>
  <a-card title="楼房分户" style="width: 600px; pointer-events: all">
    <template #extra>
      <UndoOutlined @click="refresh" />
    </template>
    <a-steps :current="currentStep" :items="steps"> </a-steps>
    <div class="draw-area">
      <span>绘制户型:</span>
      <ForkOutlined class="icon-draw" @click="activeDraw" />
      <span>{{ textDraw }}</span>
    </div>
    <div class="form-area">
      <a-table
        size="small"
        bordered
        :data-source="buildingData"
        :columns="buildingColumns"
        :pagination="false"
      >
        <template #bodyCell="{ column, text, record }">
          <template v-if="['posPrefix', 'unit'].includes(column.dataIndex)">
            <div>
              <a-input
                v-if="editableData[record.key]"
                v-model:value="editableData[record.key][column.dataIndex]"
                style="margin: -5px 0"
              />
              <template v-else>
                {{ text }}
              </template>
            </div>
          </template>

          <!-- 只有做区域绘制的时候，需要编辑 -->
          <template
            v-else-if="column.dataIndex === 'operation' && currentStep !== 2"
          >
            <div class="editable-row-operations">
              <span
                v-if="editableData[record.key]"
                style="display: flex; justify-content: space-around"
              >
                <a-typography-link @click="save(record.key)"
                  >保存</a-typography-link
                >
                <a-popconfirm
                  title="Sure to cancel?"
                  @confirm="cancel(record.key)"
                >
                  <a>取消</a>
                </a-popconfirm>
              </span>
              <span v-else>
                <a @click="edit(record.key)">编辑</a>
              </span>
            </div>
          </template>

          <!-- 只有户型切分的时候，需要定位 -->
          <template v-if="['positionFix'].includes(column.dataIndex)">
            <div @click="focusOnArea(record.key)">
              <img
                style="cursor: pointer"
                width="20"
                height="20"
                src="/src/assets/position.png"
                alt=""
              />
            </div>
          </template>
        </template>
      </a-table>
    </div>
    <!-- 楼房分层 -->
    <div class="floor-area" v-if="currentStep === 2 && showDivide">
      <span>最低点:</span>
      <a-input
        width="100"
        :value="minHeight"
        :min="-100"
        :max="200"
        :disabled="true"
      ></a-input>
      <span>分割点:</span>
      <a-input
        width="100"
        :value="divideHeight"
        :min="-100"
        :max="200"
        :disabled="true"
      ></a-input>
      <span>最高点:</span>
      <a-input
        width="100"
        :value="maxHeight"
        :min="-100"
        :max="200"
        :disabled="true"
      ></a-input>
      <span>楼层数:</span>
      <a-input
        width="100"
        v-model:value="floorNum"
        :min="0"
        :max="100"
      ></a-input>
    </div>
    <div class="button-area">
      <a-button
        v-if="currentStep < steps.length - 1"
        type="primary"
        @click="nextStep"
        >下一步</a-button
      >
      <a-button v-if="showDivide" @click="divideFloor" style="margin: 0 10px"
        >楼房分层</a-button
      >
      <a-button
        v-if="currentStep == steps.length - 1 && updateActive"
        type="primary"
        @click="updateInfo"
      >
        生成数据
      </a-button>
    </div>
  </a-card>
</template>
<style scoped>
.button-area {
  display: flex;
  justify-content: flex-end;
  margin-top: 20px;
}

.draw-area {
  margin: 20px 0;
}

.draw-area span {
  margin: 0 4px;
}

.icon-draw {
  padding: 4px;
}

.icon-draw:hover {
  cursor: pointer;
  background-color: skyblue;
  color: #fff;
}

.floor-area span {
  margin: 0 10px;
}
</style>

<script setup>
import * as Cesium from 'cesium'
import { ref, reactive, computed, watch, onBeforeUnmount } from 'vue'
import { clamp, cloneDeep, max } from 'lodash'
import { binkEntityMaterial } from '@/cesiumTools/sceneManager.js'
import {
  changeCartesin3ToGeoJson,
  polygonCut,
  cartesian3ToDegreesHeight,
} from '@/cesiumTools/utils'
import DrawTool from '../cesiumTools/drawTool'
import { UndoOutlined, ForkOutlined } from '@ant-design/icons-vue'
import { useMapData } from '@/store'
import { addHouse } from '@/api/api'
import { message } from 'ant-design-vue'

const mapStore = useMapData()
const viewer = mapStore.Viewer
const drawTool = new DrawTool(viewer)
const currentStep = ref(0)
const showDivide = ref(false)
const updateActive = ref(false)
const minHeight = ref(0)
const divideHeight = ref(0)
const maxHeight = ref(0)
const floorNum = ref(0)

// 推送到服务端的数据
// polygonJson总区域geojson字符串
// polygonJsonArr切割后geojson字符串数组，如果没有切割，传[]
// unitArr 单位数组
// heightArr 三个高度数组
// name 楼栋名称
// floorNum楼层数
let postDataSource = {
  polygonJson: '',
  polygonJsonArr: [],
  unitArr: [],
  heightArr: [],
  name: '',
  floorNum: 0,
}
// 户型设置
const buildingData = ref([])
const buildingColumns = ref([
  {
    title: '分户坐标',
    dataIndex: 'position',
    align: 'center',
    width: '30%',
    ellipsis: true,
  },
  {
    title: '地址前缀',
    dataIndex: 'posPrefix',
    align: 'center',
    width: '30%',
    ellipsis: true,
  },
  {
    title: '单位',
    dataIndex: 'unit',
    align: 'center',
  },
  {
    title: '操作',
    dataIndex: 'operation',
    align: 'center',
  },
])

const steps = ref([
  {
    title: '区域绘制',
    key: '区域绘制',
  },
  {
    title: '户型切分',
    key: '户型切分',
  },
  {
    title: '楼房分层',
    key: '楼房分层',
  },
])

watch(currentStep, (val) => {
  if (val === 0) {
    if (!buildingColumns.value.find((item) => item.dataIndex === 'operation')) {
      buildingColumns.value.push({
        title: '操作',
        dataIndex: 'operation',
        align: 'center',
      })
    }
  }
  if (val === 1) {
    if (
      !buildingColumns.value.find((item) => item.dataIndex === 'positionFix')
    ) {
      buildingColumns.value.push({
        title: '定位',
        dataIndex: 'positionFix',
        align: 'center',
        width: '10%',
      })
    }
  }
  // 楼房分层，将后面两列删除
  if (val === 2) {
    buildingColumns.value = buildingColumns.value.filter(
      (item) =>
        item.dataIndex !== 'positionFix' && item.dataIndex !== 'operation'
    )
  }
})

const editableData = reactive({})
// 可编辑表格配置
const edit = (key) => {
  editableData[key] = cloneDeep(
    buildingData.value.filter((item) => key === item.key)[0]
  )
}
const save = (key) => {
  Object.assign(
    buildingData.value.filter((item) => key === item.key)[0],
    editableData[key]
  )
  delete editableData[key]
}
const cancel = (key) => {
  delete editableData[key]
}

const textDraw = computed(() => {
  let res = ''
  switch (currentStep.value) {
    case 0:
      res = '绘制图形'
      break
    case 1:
      res = '户型裁剪'
      break
    case 2:
      res = '楼层分层'
      break
    default:
      break
  }
  return res
})

const refresh = () => {
  if (buildPrimitives.length) {
    buildPrimitives.forEach((p) => viewer.scene.primitives.remove(p))
    buildPrimitives = []
  }
  viewer.entities.removeAll()
  currentStep.value = 0
  postDataSource = {
    polygonJson: '',
    polygonJsonArr: [],
    unitArr: [],
    heightArr: [],
    name: '',
    floorNum: 0,
  }
  updateActive.value = false
  showDivide.value = false
  buildingData.value = []
  drawEndEvent && drawTool.removeListener(drawEndEvent)
  drawTool.removeAllDrawEnts()
}

const nextStep = () => {
  if (buildingData.value.length) currentStep.value++
  else message.warn('请先绘制区域')
}

const focusOnArea = (key) => {
  console.log(key)
  const targetEntity = viewer.entities.values.find((item) => item.name === key)
  if (targetEntity) {
    binkEntityMaterial(targetEntity)
  }
}

const updateInfo = async () => {
  postDataSource.unitArr = buildingData.value.map((item) => Number(item.unit))
  postDataSource.heightArr = [
    minHeight.value,
    divideHeight.value,
    maxHeight.value,
  ]
  postDataSource.name = buildingData.value[0].posPrefix
  postDataSource.floorNum = Number(floorNum.value)
  const res = await addHouse(postDataSource)
  if (res.code === 200) {
    console.log(res, 'res')
    message.success('分户成功')
    refresh()
  } else {
    message.error('分户失败')
  }
}

let buildPrimitives = []
const divideFloor = () => {
  console.log(currentStep.value, 'currentStep')
  if (floorNum.value > 1) {
    const itemHeight =
      (maxHeight.value - divideHeight.value) / (floorNum.value - 1)
    buildingData.value.forEach((item) => {
      const { position } = item
      const positionArr = position.split(',').map((item) => Number(item))
      const cartesian = new Cesium.Cartesian3.fromDegreesArray(positionArr)
      const hierachy = new Cesium.PolygonHierarchy(cartesian)
      for (let i = 0; i < floorNum.value; i++) {
        let height, extrudedHeight
        if (i === 0) {
          height = minHeight.value
          extrudedHeight = divideHeight.value
        } else {
          height = divideHeight.value + (i - 1) * itemHeight
          extrudedHeight = divideHeight.value + i * itemHeight
        }

        const geometryInstance = new Cesium.GeometryInstance({
          geometry: new Cesium.PolygonGeometry({
            polygonHierarchy: hierachy,
            height,
            extrudedHeight,
          }),
          attributes: {
            color: Cesium.ColorGeometryInstanceAttribute.fromColor(
              Cesium.Color.fromRandom({ alpha: 0.3 }) //颜色
            ),
          },
        })

        const p = new Cesium.ClassificationPrimitive({
          geometryInstances: geometryInstance,
          classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
        })
        viewer.scene.primitives.add(p)
        buildPrimitives.push(p)
      }
    })
    updateActive.value = true
  }
}

let polygonGeo
let drawEndEvent
let lastDrawEnt
const activeDraw = () => {
  if (currentStep.value === 0) {
    drawTool.active(drawTool.DrawTypes.Polygon)
    drawEndEvent = (ent, positions) => {
      const { geojson, positionLng } = changeCartesin3ToGeoJson(
        positions,
        'polygon'
      )
      if (geojson) {
        lastDrawEnt = ent
        polygonGeo = geojson
        buildingData.value[0] = {
          position: positionLng.join(','),
          posPrefix: 'xxx小区xxx楼栋',
          unit: '1',
        }
        postDataSource.polygonJson = JSON.stringify(geojson.geometry)
      }
      drawEndEvent && drawTool.removeListener(drawEndEvent)
    }
    drawTool.DrawEndEvent.addEventListener(drawEndEvent)
  } else if (currentStep.value === 1) {
    drawTool.active(drawTool.DrawTypes.Polyline)
    drawEndEvent = (ent, positions) => {
      if (polygonGeo) {
        const { geojson: lineJson } = changeCartesin3ToGeoJson(
          positions,
          'polyline'
        )
        const featureCollection = polygonCut(polygonGeo, lineJson)
        console.log(featureCollection)
        if (featureCollection) {
          lastDrawEnt && viewer.entities.remove(lastDrawEnt)
          drawTool.removeAllDrawEnts()
          console.log(featureCollection)

          postDataSource.polygonJsonArr = featureCollection.features.map(
            (item) => {
              return JSON.stringify(item.geometry)
            }
          )
          new Cesium.GeoJsonDataSource()
            .load(featureCollection, { clampToGround: true })
            .then((dataSource) => {
              //   viewer.dataSource.add(dataSource)
              let tableData = []
              dataSource.entities.values.forEach((item, index) => {
                item.polygon.material = new Cesium.Color.fromRandom({
                  alpha: 0.5,
                })
                item.name = index
                tableData.push({
                  key: index,
                  position:
                    featureCollection.features[
                      index
                    ].geometry.coordinates.toString(),
                  posPrefix: buildingData.value[0].posPrefix,
                  unit: index + 1,
                })
                viewer.entities.add(item)
              })
              buildingData.value = tableData
            })
        }
      }
      drawEndEvent && drawTool.removeListener(drawEndEvent)
    }
    drawTool.DrawEndEvent.addEventListener(drawEndEvent)
  } else if (currentStep.value === 2) {
    drawTool.active(drawTool.DrawTypes.Point)
    drawEndEvent = (ent, positions) => {
      if (positions.length !== 3) {
        message.warn('请绘制底层，二楼，顶楼三个位置的高度')
        return
      }
      const heightArr = positions
        .map((position) => {
          const positionLng = cartesian3ToDegreesHeight(position)
          return positionLng[2]
        })
        .sort((a, b) => a - b)

      minHeight.value = heightArr[0]
      divideHeight.value = heightArr[1]
      maxHeight.value = heightArr[2]
      showDivide.value = true
      drawEndEvent && drawTool.removeListener(drawEndEvent)
    }
    drawTool.DrawEndEvent.addEventListener(drawEndEvent)
  }
}

//切换别的组件之前，将未保存的绘制清除
onBeforeUnmount(() => {
  refresh()
})
</script>
